#ifndef UTILS_H
#define UTILS_H
#include <gmp.h>
#include <gmpxx.h>
#include <unordered_set>
#include "numb.h"

uint64_t ModExp(uint64_t x, uint64_t e, uint64_t p);

bool EqualSliceUint64(const std::vector<uint64_t> &a, const std::vector<uint64_t> &b);

uint64_t BitReverse64(uint64_t x, uint64_t bitLen);

bool AllDistinct(const std::vector<uint64_t> &s);

int BitsLen64(uint64_t x);

bool IsPrime(uint64_t x);

std::vector<uint64_t> GenerateNTTPrimesP(uint64_t logP, uint64_t NthRoot, uint64_t n);

mpz_class NewUint(unsigned long int v);

uint64_t MaxSliceUint64(std::vector<uint64_t> slice, int len);

std::vector<uint64_t> RotateUint64Slots(std::vector<uint64_t> s, int64_t k);

std::vector<uint64_t> RotateUint64Slice(std::vector<uint64_t> s, int64_t k);

uint64_t SubUintMod(uint64_t operand1, uint64_t operand2, const uint64_t &modulus);

uint64_t MultiplyUintMod(uint64_t operand1, uint64_t operand2, const uint64_t &modulus);

uint64_t NegateUintMod(uint64_t base, const uint64_t &modulus);

uint64_t AddUintMod(uint64_t operand1, uint64_t operand2, const uint64_t &modulus);

uint64_t Exponentiate(uint64_t base, uint64_t exp);


enum MultiType { ciphertext, plaintext, plaintextRingT, plaintextMul };

#endif // UTILS_H
